home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / dev / misc / gms_sound.lha / Sound / asmsound.s < prev    next >
Encoding:
Text File  |  1998-10-10  |  21.8 KB  |  716 lines

  1. ;=======T=======T========================T==========================================;
  2. ;                                   SOUND MODULE
  3. ;===================================================================================;
  4.  
  5.     xref    _LIBFreeSoundMem
  6.     xref    _LIBAllocSoundMem
  7.     xref    _DPKBase
  8.     xref    _SndAlloc
  9.     xref    _Octaves
  10.     xref    _Volumes
  11.  
  12.     xdef    _LIBAllocAudio
  13.     xdef    _LIBFreeAudio
  14.     xdef    _LIBSetVolume
  15.     xdef    _LIBStopAudio
  16.     xdef    _LIBCheckSound
  17.     xdef    _SND_Deactivate
  18.     xdef    _SND_Activate
  19.  
  20.     INCDIR    "INCLUDES:"
  21.     INCLUDE    "exec/exec_lib.i"
  22.     INCLUDE    "hardware/custom.i"
  23.     INCLUDE    "dpkernel/dpkernel.i"
  24.     INCLUDE    "system/tracking.i"
  25.     INCLUDE    "sound/sound.i"
  26.  
  27.     SECTION "ModCode",CODE
  28.  
  29. ;===================================================================================;
  30. ;                         ALLOCATE AUDIO CHANNELS
  31. ;===================================================================================;
  32. ;Function: LONG AllocAudio(void)
  33. ;Short:    Attempts to allocate all the audio channels.
  34.  
  35. _LIBAllocAudio:
  36.     MOVEM.L    D1-D7/A0-A6,-(SP)    ;SP = Save all registers.
  37.     move.l    _DPKBase,a6    ;a6 = DPKBase.
  38.  
  39.     tst.w    _SndAlloc    ;ma =  Check if already allocated.
  40.     bne.s    .done    ;>> = Yes, so just exit.
  41.  
  42.     move.l    $4.w,a6    ;a6 = ExecBase.
  43.     CALL    Forbid    ;>> = Forbid the system.
  44.     moveq    #-1,d0    ;d0 = -1
  45.     CALL    AllocSignal    ;>> = Get a signal?
  46.     tst.b    d0    ;d0 = Did we get it?
  47.     bmi.s    .Error    ;>> = Error.
  48.     move.b    d0,SigBitNum    ;ma = Store bit number.
  49.  
  50.     ;Prepare IORequest
  51.  
  52.     lea    AllocPort(pc),a1    ;a1 = Port.
  53.     move.b    d0,15(a1)    ;a1 = Set mp_SigBit
  54.     move.l    a1,-(SP)    ;
  55.     suba.l    a1,a1    ;
  56.     CALL    FindTask    ;>> = Find our task.
  57.     move.l    (SP)+,a1
  58.     move.l    d0,16(a1)    ;a1 = Set mp_SigTask
  59.     lea    ReqList(pc),a0
  60.     move.l    a0,(a0)    ;a0 = NEWLIST begins...
  61.     addq.l    #4,(a0)    ;a0 = +4
  62.     clr.l    4(a0)    ;a0 = Clear
  63.     move.l    a0,8(a0)    ;a0 = NEWLIST ends...
  64.  
  65.     ;Open the audio.device (attempt all channels).
  66.  
  67.     moveq    #2,d2    ;d2 = 2.
  68.     lea    AllocReq(pc),a1    ;a1 = Ptr to AllocReq.
  69.     lea    AUD_Name(pc),a0    ;a0 = Ptr to AudioDeviceName
  70.     moveq    #0,d0    ;d0 = 00.
  71.     moveq    #0,d1    ;d1 = 00.
  72.     move.l    ($4).w,a6    ;a6 = ExecBase.
  73.     CALL    OpenDevice    ;>> = Open Audio device.
  74.     tst.b    d0    ;d0 = Check for error.
  75.     bne.s    .Error    ;>> = Error, audio in use.
  76.     st    AudioDevOpen    ;MA = Yes, we managed to open it.
  77.     move.l    ($4).w,a6    ;a6 = ExecBase.
  78.     CALL    Permit    ;>> = Permit the system.
  79.  
  80.     or.b    #2,($bfe001).L    ;ma = Turn Sound filter OFF.
  81.     move.w    #1,_SndAlloc    ;ma = Note allocation.
  82.  
  83. .done    MOVEM.L    (SP)+,D1-D7/A0-A6    ;SP = Return all registers.
  84.     moveq    #ERR_OK,d0    ;d0 = No errors.
  85.     rts
  86.  
  87. .Error    MOVEM.L    (SP)+,D1-D7/A0-A6    ;SP = Return all registers.
  88.     moveq    #ERR_INUSE,d0    ;d0 = Error, audio in use.
  89.     rts
  90.  
  91. ;===================================================================================;
  92. ;                           FREE AUDIO CHANNELS
  93. ;===================================================================================;
  94. ;Function: void FreeAudio(void)
  95. ;Short:    Free the audio channels so the system can use them again.
  96.  
  97. _LIBFreeAudio:
  98.     MOVEM.L    A0-A6/D0-D7,-(SP)
  99.     move.l    _DPKBase,a6    ;a6 = DPKBase.
  100.     tst.w    _SndAlloc    ;ma = Check if we actually own it.
  101.     beq.s    .done    ;>> = Nope, exit.
  102.     bsr    _LIBStopAudio
  103.     move.l    ($4).w,a6    ,a6 = ExecBase.
  104.     tst.b    AudioDevOpen    ;MA = Is it actually open?
  105.     beq.s    .rem1    ;>> = No!
  106.     move.w    #$000f,$dff096    ;MA = Stop audio DMA
  107.     lea    AllocReq(pc),a1    ;a1 = 
  108.     CALL    CloseDevice    ;>> = Close audio.device
  109.  
  110.     clr.b    AudioDevOpen    ;MA = No longer open.
  111. .rem1    moveq    #0,d0    ;d0 = 00.
  112.     move.b    SigBitNum(pc),d0    ;d0 = Signal.
  113.     bmi.s    .rem2    ;>> = No signal.
  114.     CALL    FreeSignal    ;>> = Free it.
  115.     st    SigBitNum    ;MA = We don't have it anymore.
  116. .rem2    and.b    #253,($bfe001).l    ;MA = Turn Sound filter back ON.
  117.     clr.w    _SndAlloc
  118. .done    MOVEM.L    (SP)+,A0-A6/D0-D7    ;SP = Return all registers.
  119.     rts
  120.  
  121. ;===================================================================================;
  122. ;                   PLAY SOUND ACCORDING TO PRIORITIES
  123. ;===================================================================================;
  124. ;Function: LONG Activate(*Sound [a0])
  125. ;Short:    Play a sound through a channel if it passes the priority test.
  126.  
  127. _SND_Activate:
  128.     MOVE.L    A6,-(SP)    ;SP = Save registers.
  129.     lea    $dff000,a6    ;a6 = $dff000.
  130.     move.l    SND_Attrib(a0),d0    ;d0 = Sound attributes.
  131.     and.l    #SDF_STOPLAST,d0    ;d0 = Should the last play be stopped?
  132.     beq.s    .FindChannel    ;>> = Nope, leave it.
  133.  
  134.     ;Deactivate the last channel if the sound is still playing.
  135.     ;This means disabling the channel that the sound last went
  136.     ;through.
  137.  
  138.     move.w    SNDP_LastChannel(a0),d0    ;d0 = Channel number to play in.
  139.     beq.s    .FindChannel
  140.     add.w    d0,d0    ;d0 = ChanNum*2.
  141.     move.w    d0,d1    ;d1 = (ChanNum)*2
  142.     add.w    d1,d1    ;d1 = (ChanNum)*4
  143.     lea    ChannelSounds(pc),a1    ;a1 = &ChannelSounds array.
  144.     cmp.l    (a1,d1.w),a0    ;a1 = Is our sound "still playing"?
  145.     bne.s    .FindChannel    ;>> = We can play through any channel.
  146.     move.w    .Jump(pc,d0.w),d0    ;d0 = Jump offset.
  147.     jmp    .Jump(pc,d0.w)    ;>> = Play through previous channel.
  148.  
  149. .Jump    dc.w    PSPri1-.Jump    ;0 (This channel is actually illegal).
  150.     dc.w    PSPri1-.Jump    ;1
  151.     dc.w    PSPri2-.Jump    ;2
  152.     dc.w    PSPri3-.Jump    ;3
  153.     dc.w    PSPri4-.Jump    ;4
  154.  
  155. .FindChannel
  156.     clr.w    SNDP_LastChannel(a0)    ;a0 = Clear last channel.
  157.     lea    ChannelPri(pc),a1    ;a1 = Pointer to current priorites.
  158.     move.w    INTREQR(a6),d0    ;d0 = INTREQR.
  159.  
  160.     ;Test for channel preference.
  161.  
  162.     move.l    SND_Attrib(a0),d1    ;d1 = Sound attributes.
  163.     btst    #SDB_RIGHT,d1    ;d1 = Prefer right?
  164.     bne.s    .rightfirst    ;>> = Yes.
  165.     btst    #SDB_LEFT,d1    ;d1 = Prefer left?
  166.     bne.s    .leftfirst    ;>> = Yes.
  167. .anyfirst
  168.     btst    #7,d0    ;d0 = Test left.
  169.     bne.s    Pspi1    ;>> = Left available.
  170.     btst    #8,d0    ;d0 = Test right.
  171.     bne    Pspi2    ;>> = Right available.
  172.     btst    #9,d0    ;d0 = Test right.
  173.     bne    Pspi3    ;>> = Right available.
  174.     btst    #10,d0    ;d0 = Test left.
  175.     bne    Pspi4    ;>> = Left available.
  176.     bra.s    .priorities
  177.  
  178. ;-----------------------------------------------------------------------------------;
  179. ;Right is preferred.
  180.  
  181. .rightfirst
  182.     btst    #8,d0    ;d0 = Test right.
  183.     bne    Pspi2    ;>> = Right available.
  184.     btst    #9,d0    ;d0 = Test right.
  185.     bne    Pspi3    ;>> = Right available.
  186.     btst    #SDB_FORCE,d1    ;d1 = Force on right?
  187.     bne.s    .rightpriforce    ;>> = Yes, so skip left channels.
  188.     btst    #7,d0    ;d0 = Test left.
  189.     bne.s    Pspi1    ;>> = Left available.
  190.     btst    #10,d0    ;d0 = Test left.
  191.     bne    Pspi4    ;>> = Left available.
  192.     bra.s    .priorities
  193.  
  194. .rightpriforce
  195.     btst    #SDB_EMPTY,d1    ;d1 = Only play if channels are empty?
  196.     bne.s    .done    ;>> = Since there are none empty, exit.
  197.     move.w    SND_Priority(a0),d0    ;d0 = Sample Priority.
  198.     cmp.w    2(a1),d0    ;
  199.     bgt    Pspi2    ;>> = Chan2, Only play if greater (right)
  200.     cmp.w    4(a1),d0    ;
  201.     bge    Pspi3    ;>> = Chan3, Only play if greater/equal (right)
  202.     bra.s    .done
  203.  
  204. ;-----------------------------------------------------------------------------------;
  205. ;Left is preferred.
  206.  
  207. .leftfirst
  208.     btst    #7,d0    ;d0 = Test left.
  209.     bne.s    Pspi1    ;>> = Left available.
  210.     btst    #10,d0    ;d0 = Test left.
  211.     bne    Pspi4    ;>> = Left available.
  212.     btst    #SDB_FORCE,d1    ;d1 = Force on left?
  213.     bne.s    .leftpriforce    ;>> = Yes, so skip right channels.
  214.     btst    #8,d0    ;d0 = Test right.
  215.     bne    Pspi2    ;>> = Right available.
  216.     btst    #9,d0    ;d0 = Test right.
  217.     bne    Pspi3    ;>> = Right available.
  218.     bra.s    .priorities
  219.  
  220. .leftpriforce
  221.     btst    #SDB_EMPTY,d1    ;d1 = Only play if channels are empty?
  222.     bne.s    .done    ;>> = Since there are none empty, exit.
  223.     move.w    SND_Priority(a0),d0    ;d0 = Sample Priority.
  224.     cmp.w    (a1),d0    ;a1 = < SamplePri?
  225.     bgt.s    Pspi1    ;>> = Chan1, Only play if greater (left)
  226.     cmp.w    6(a1),d0    ;
  227.     bge    Pspi4    ;>> = Chan4, Only play if greater/equal (left)
  228.     bra.s    .done    ;
  229.  
  230. ;-----------------------------------------------------------------------------------;
  231. ;If no channels are available, compare the priorities.
  232. ;
  233. ;Requires: d1 = Sound attributes.
  234.  
  235. .priorities
  236.     btst    #SDB_EMPTY,d1    ;d1 = Only play if channels are empty?
  237.     bne.s    .done    ;>> = Since there are none empty, exit.
  238.  
  239.     move.w    SND_Priority(a0),d0    ;d0 = Sample Priority.
  240.     cmp.w    (a1),d0    ;a1 = < SamplePri?
  241.     bgt.s    Pspi1    ;>> = Chan1, Only play if greater (left)
  242.     cmp.w    2(a1),d0    ;
  243.     bgt    Pspi2    ;>> = Chan2, Only play if greater (right)
  244.     cmp.w    6(a1),d0    ;
  245.     bge    Pspi4    ;>> = Chan4, Only play if greater/equal (left)
  246.     cmp.w    4(a1),d0    ;
  247.     bge    Pspi3    ;>> = Chan3, Only play if greater/equal (right)
  248. .done    MOVE.L    (SP)+,A6    ;a6 = Return registers.
  249.     moveq    #ERR_FAILED,d0    ;d0 = Error, failed.
  250.     rts        ;Exit.
  251.  
  252. ;-----------------------------------------------------------------------------------;
  253. ;                                     CHANNEL 1
  254. ;-----------------------------------------------------------------------------------;
  255.  
  256. PSPri1:    lea    ChannelPri(pc),a1    ;a1 = Pointer to current priorites.
  257.     lea    $dff000,a6
  258.     btst    #7,INTREQR+1(a6)    ;a6 = Test channel - is it in use?  If
  259.     bne.s    Pspi1    ;     not, ignore channel priority.
  260.     move.w    (a1),d1    ;d1 = Current sound priority.
  261.     cmp.w    SND_Priority(a0),d1
  262.     bgt    PS1done
  263.  
  264. Pspi1:    move.w    #1,SNDP_LastChannel(a0)    ;a0 = Set last channel.
  265.     move.w    SND_Priority(a0),(a1)    ;a1 = Store new priority.
  266.     move.w    #$0001,DMACON(a6)    ;a6 = Turn off channel ($0001)
  267.     move.w    #$8000+1<<7,INTREQ(a6)    ;a6 = Request reset of audio interrupt.
  268.     moveq    #80-1,d1    ;d1 = vsync counters to wait.
  269. .wait0    move.b    $7(a6),d0    ;d0 = Waits about 3.4 scan lines.
  270. .wait1    cmp.b    $7(a6),d0
  271.     beq.s    .wait1
  272.     dbra    d1,.wait0
  273.  
  274.     move.l    SND_Data(a0),AUD0LC(a6)
  275.     move.l    SND_Length(a0),d0
  276.     lsr.l    #1,d0
  277.     move.w    d0,AUD0LEN(a6)
  278.  
  279.     lea    _Octaves,a1
  280.     move.w    SND_Octave(a0),d0
  281.     move.w    (a1,d0.w),AUD0PER(a6)
  282.  
  283.     lea    _Volumes,a1
  284.     move.w    SND_Volume(a0),d0
  285.     add.w    d0,d0    ;d0 = (Volume)*2 [word]
  286.     move.w    (a1,d0.w),AUD0VOL(a6)
  287.     move.w    (a1,d0.w),Chan1Vol
  288.  
  289.     ;Check volume modulation.  Channel 1 is
  290.     ;modulated with channel 2.
  291.  
  292. .chkvol    move.w    #(1<<0),ADKCON(a6)
  293.     move.l    SND_Attrib(a0),d1
  294.     btst    #SDB_MODVOL,d1
  295.     beq.s    .chkper
  296.     move.w    #(1<<15)!(1<<0),ADKCON(a6)
  297.  
  298.     ;Check period modulation.  Channel 1 is
  299.     ;modulated with channel 2.
  300.  
  301. .chkper    move.w    #(1<<4),ADKCON(a6)
  302.     move.l    SND_Attrib(a0),d1
  303.     btst    #SDB_MODPER,d1
  304.     beq.s    .chanon
  305.     move.w    #(1<<15)!(1<<4),ADKCON(a6)
  306.  
  307.     ;Turn the channel on so that the sound
  308.     ;plays.
  309.  
  310. .chanon    move.w    #$8001,DMACON(a6)    ;Turn channel on. ($8001)
  311.     move.l    SND_Attrib(a0),d1
  312.     btst    #SDB_REPEAT,d1
  313.     bne.s    PS1done
  314.     moveq    #40-1,d1    ;d1 = vsync counters to wait - 1
  315. .wait2    move.b    $7(a6),d0    ;Waits only about 1.7 scan lines.
  316. .wait3    cmp.b    $7(a6),d0
  317.     beq.s    .wait3
  318.     dbra    d1,.wait2
  319.     move.w    #1<<7,INTREQ(a6)    ;Turn off audio interrupt check.
  320.     move.l    #ChipZero,AUD0LC(a6)    ;Once audio has recognised us we
  321.     move.w    #2,AUD0LEN(a6)    ;point the data to zeros.
  322. PS1done:
  323.     MOVE.L    (SP)+,A6
  324.     move.l    a0,CS1    ;ma = Note successful sound.
  325.  
  326.     ;If we need to modulate the sound, we need
  327.     ;to play the Paired sound through channel 2.
  328.  
  329.     move.l    SND_Attrib(a0),d1
  330.     and.l    #SDF_MODVOL|SDF_MODPER,d1
  331.     beq.s    .done
  332.     move.l    SND_Pair(a0),a0
  333.     bsr    Pspi2
  334.  
  335. .done    moveq    #ERR_OK,d0
  336.     rts
  337.  
  338. ;-----------------------------------------------------------------------------------;
  339. ;                                     CHANNEL 2
  340. ;-----------------------------------------------------------------------------------;
  341.  
  342. PSPri2:    lea    ChannelPri(pc),a1    ;a1 = Pointer to current priorites.
  343.     lea    $dff000,a6
  344.     btst    #0,INTREQR(a6)    ;Test channel - is it in use?  If
  345.     bne.s    Pspi2    ;  not, ignore channel priority.
  346.     move.w    2(a1),d1    ;d1 = Current sound priority.
  347.     cmp.w    SND_Priority(a0),d1
  348.     bgt.s    PS1done
  349.  
  350. Pspi2:    move.w    #2,SNDP_LastChannel(a0)    ;a0 = Set last channel.
  351.     move.w    SND_Priority(a0),2(a1)    ;Store new priority.
  352.     move.w    #$0002,DMACON(a6)    ;Turn off channel.
  353.     move.w    #$8000+1<<8,INTREQ(a6)    ;Request reset of audio interrupt.
  354.     moveq    #80-1,d1    ;d1 = vsync counters to wait.
  355. .wait0    move.b    $7(a6),d0    ;Waits about 3.4 scan lines.
  356. .wait1    cmp.b    $7(a6),d0
  357.     beq.s    .wait1
  358.     dbra    d1,.wait0
  359.     move.l    SND_Data(a0),AUD1LC(a6)
  360.     move.l    SND_Length(a0),d0
  361.     lsr.l    #1,d0
  362.     move.w    d0,AUD1LEN(a6)
  363.     move.w    SND_Octave(a0),d0
  364.     lea    _Octaves,a1
  365.     move.w    (a1,d0.w),AUD1PER(a6)
  366.  
  367.     lea    _Volumes,a1
  368.     move.w    SND_Volume(a0),d0
  369.     add.w    d0,d0    ;d0 = (Volume)*2 [word]
  370.     move.w    (a1,d0.w),AUD1VOL(a6)
  371.     move.w    (a1,d0.w),Chan2Vol
  372.  
  373. .chkvol    move.w    #(1<<1),ADKCON(a6)
  374.     move.l    SND_Attrib(a0),d1
  375.     btst    #SDB_MODVOL,d1
  376.     beq.s    .chkper
  377.     move.w    #(1<<15)!(1<<1),ADKCON(a6)
  378.  
  379. .chkper    move.w    #(1<<5),ADKCON(a6)
  380.     move.l    SND_Attrib(a0),d1
  381.     btst    #SDB_MODPER,d1
  382.     beq.s    .chanon
  383.     move.w    #(1<<15)!(1<<5),ADKCON(a6)
  384.  
  385. .chanon    move.w    #$8002,DMACON(a6)    ;Turn channel on. ($8001)
  386.     move.l    SND_Attrib(a0),d1
  387.     btst    #SDB_REPEAT,d1
  388.     bne.s    PS2done
  389.     moveq    #40-1,d1    ;d1 = vsync counters to wait - 1
  390. .wait2    move.b    $7(a6),d0    ;Waits only about 1.7 scan lines.
  391. .wait3    cmp.b    $7(a6),d0
  392.     beq.s    .wait3
  393.     dbra    d1,.wait2
  394.     move.w    #1<<8,INTREQ(a6)    ;Turn off audio interrupt check.
  395.     move.l    #ChipZero,AUD1LC(a6)    ;Once audio has recognised us we
  396.     move.w    #2,AUD1LEN(a6)    ;point the data to zeros.
  397.  
  398. PS2done    MOVE.L    (SP)+,A6
  399.     move.l    a0,CS2    ;ma = Note successful sound play.
  400.  
  401.     ;If we need to modulate the sound, we have
  402.     ;to play the Paired sound through the next channel.
  403.  
  404.     move.l    SND_Attrib(a0),d1
  405.     and.l    #SDF_MODVOL|SDF_MODPER,d1
  406.     beq.s    .done
  407.     move.l    SND_Pair(a0),a0
  408.     bsr    Pspi3
  409.  
  410. .done    moveq    #ERR_OK,d0
  411.     rts
  412.  
  413. ;-----------------------------------------------------------------------------------;
  414. ;                                     CHANNEL 3
  415. ;-----------------------------------------------------------------------------------;
  416.  
  417. PSPri3:    lea    ChannelPri(pc),a1    ;a1 = Pointer to current priorites.
  418.     lea    $dff000,a6
  419.     btst    #1,INTREQR(a6)    ;Test channel - is it in use?  If
  420.     bne.s    Pspi3    ;  not, ignore channel priority.
  421.     move.w    4(a1),d1    ;d1 = Current sound priority.
  422.     cmp.w    SND_Priority(a0),d1
  423.     bgt.s    PS2done
  424.  
  425. Pspi3:    move.w    #3,SNDP_LastChannel(a0)    ;a0 = Set last channel.
  426.     move.w    SND_Priority(a0),4(a1)    ;Store new priority.
  427.     move.w    #$0004,DMACON(a6)    ;Turn off channel ($0001)
  428.     move.w    #$8000+1<<9,INTREQ(a6)    ;Request reset of audio interrupt.
  429.     moveq    #80-1,d1    ;d1 = vsync counters to wait.
  430. .wait0    move.b    $7(a6),d0    ;Waits about 3.4 scan lines.
  431. .wait1    cmp.b    $7(a6),d0
  432.     beq.s    .wait1
  433.     dbra    d1,.wait0
  434.     move.l    SND_Data(a0),AUD2LC(a6)
  435.     move.l    SND_Length(a0),d0
  436.     lsr.l    #1,d0
  437.     move.w    d0,AUD2LEN(a6)
  438.     move.w    SND_Octave(a0),d0
  439.     lea    _Octaves,a1
  440.     move.w    (a1,d0.w),AUD2PER(a6)
  441.  
  442.     lea    _Volumes,a1
  443.     move.w    SND_Volume(a0),d0
  444.     add.w    d0,d0    ;d0 = (Volume)*2 [word]
  445.     move.w    (a1,d0.w),AUD2VOL(a6)
  446.     move.w    (a1,d0.w),Chan3Vol
  447.  
  448. .chkvol    move.w    #(1<<2),ADKCON(a6)
  449.     move.l    SND_Attrib(a0),d1
  450.     btst    #SDB_MODVOL,d1
  451.     beq.s    .chkper
  452.     move.w    #(1<<15)!(1<<2),ADKCON(a6)
  453.  
  454. .chkper    move.w    #(1<<6),ADKCON(a6)
  455.     move.l    SND_Attrib(a0),d1
  456.     btst    #SDB_MODPER,d1
  457.     beq.s    .chanon
  458.     move.w    #(1<<15)!(1<<6),ADKCON(a6)
  459.  
  460. .chanon    move.w    #$8004,DMACON(a6)    ;Turn channel on. ($8001)
  461.     move.l    SND_Attrib(a0),d1
  462.     btst    #SDB_REPEAT,d1
  463.     bne.s    PS3done
  464.     moveq    #40-1,d1    ;d1 = vsync counters to wait - 1
  465. .wait2    move.b    $7(a6),d0    ;Waits only about 1.7 scan lines.
  466. .wait3    cmp.b    $7(a6),d0
  467.     beq.s    .wait3
  468.     dbra    d1,.wait2
  469.     move.w    #1<<9,INTREQ(a6)    ;Turn off audio interrupt check.
  470.     move.l    #ChipZero,AUD2LC(a6)    ;Once audio has recognised us we
  471.     move.w    #2,AUD2LEN(a6)    ;point the data to zeros.
  472. PS3done    MOVE.L    (SP)+,A6
  473.     move.l    a0,CS3    ;ma = Note successful sound play.
  474.  
  475.     ;If we need to modulate the sound, we have
  476.     ;to play the Paired sound through the next channel.
  477.  
  478.     move.l    SND_Attrib(a0),d1
  479.     and.l    #SDF_MODVOL|SDF_MODPER,d1
  480.     beq.s    .done
  481.     move.l    SND_Pair(a0),a0
  482.     bsr    Pspi4
  483.  
  484. .done    moveq    #ERR_OK,d0
  485.     rts
  486.  
  487. ;-----------------------------------------------------------------------------------;
  488. ;                                     CHANNEL 4
  489. ;-----------------------------------------------------------------------------------;
  490. ;Note: Channel 4 cannot modulate anything.
  491.  
  492. PSPri4:    lea    ChannelPri(pc),a1    ;a1 = Pointer to current priorites.
  493.     lea    $dff000,a6
  494.     btst    #2,INTREQR(a6)    ;Test channel - is it in use?  If
  495.     bne.s    Pspi4    ;  not, ignore channel priority.
  496.     move.w    6(a1),d1    ;d1 = Current sound priority.
  497.     cmp.w    SND_Priority(a0),d1
  498.     bgt.s    PS3done
  499.  
  500. Pspi4:    move.w    #4,SNDP_LastChannel(a0)    ;a0 = Set last channel.
  501.     move.w    SND_Priority(a0),6(a1)    ;Store new priority.
  502.     move.w    #$0008,DMACON(a6)    ;Turn off channel ($0001)
  503.     move.w    #$8000+1<<10,INTREQ(a6)    ;Request reset of audio interrupt.
  504.     moveq    #80-1,d1    ;d1 = vsync counters to wait.
  505. .wait0    move.b    $7(a6),d0    ;Waits about 3.4 scan lines.
  506. .wait1    cmp.b    $7(a6),d0
  507.     beq.s    .wait1
  508.     dbra    d1,.wait0
  509.     move.l    SND_Data(a0),AUD3LC(a6)
  510.     move.l    SND_Length(a0),d0
  511.     lsr.l    #1,d0
  512.     move.w    d0,AUD3LEN(a6)
  513.     move.w    SND_Octave(a0),d0    ;d0 = Octave number.
  514.     lea    _Octaves,a1
  515.     move.w    (a1,d0.w),AUD3PER(a6)
  516.  
  517.     lea    _Volumes,a1
  518.     move.w    SND_Volume(a0),d0    ;d0 = Volume
  519.     add.w    d0,d0    ;d0 = (Volume)*2 [word]
  520.     move.w    (a1,d0.w),AUD3VOL(a6)
  521.     move.w    (a1,d0.w),Chan4Vol
  522.  
  523.     move.w    #$8008,DMACON(a6)    ;Turn channel on. ($8001)
  524.     move.l    SND_Attrib(a0),d1
  525.     btst    #SDB_REPEAT,d1
  526.     bne.s    PS4done
  527.     moveq    #40-1,d1    ;d1 = vsync counters to wait - 1
  528. .wait2    move.b    $7(a6),d0    ;Waits only about 1.7 scan lines.
  529. .wait3    cmp.b    $7(a6),d0
  530.     beq.s    .wait3
  531.     dbra    d1,.wait2
  532.     move.w    #1<<10,INTREQ(a6)    ;Turn off audio interrupt check.
  533.     move.l    #ChipZero,AUD3LC(a6)    ;Once audio has recognised us we
  534.     move.w    #2,AUD3LEN(a6)    ;point the data to zeros.
  535.  
  536. PS4done    MOVE.L    (SP)+,A6
  537.     move.l    a0,CS4    ;ma = Note successful sound play.
  538.     moveq    #ERR_OK,d0
  539.     rts
  540.  
  541. ;===================================================================================;
  542. ;                               STOP SOUND
  543. ;===================================================================================;
  544. ;Function: void Deactivate(*Sound [a0])
  545. ;Short:    Stops a Sound from playing any further.  All we are really doing is
  546. ;       changing the volume to zero though :-)
  547.  
  548. _SND_Deactivate:
  549.     move.w    SNDP_LastChannel(a0),d0    ;d0 = Last channel.
  550.     add.w    d0,d0    ;d0 = *2
  551.     add.w    d0,d0    ;d0 = *4
  552.     lea    ChannelSounds(pc),a1    ;a1 = &ChannelSounds array.
  553.     cmp.l    (a1,d0.w),a0    ;a0 = Our sound still in play?
  554.     bne.s    .notplaying    ;>> = Someone else is in the channel.
  555.     move.l    VolTable(pc,d0.w),a1    ;d0 = Volume hardware address.
  556.     move.w    #0,(a1)    ;a1 = Set the audio volume to 0.
  557. .notplaying
  558.     rts
  559.  
  560. VolTable:
  561.     dc.l    $dff000+AUD0VOL    ;0 [Not relevant]
  562.     dc.l    $dff000+AUD0VOL    ;1
  563.     dc.l    $dff000+AUD1VOL    ;2
  564.     dc.l    $dff000+AUD2VOL    ;3
  565.     dc.l    $dff000+AUD3VOL    ;4
  566.  
  567. ;===================================================================================;
  568. ;                            STOP ALL CHANNELS
  569. ;===================================================================================;
  570. ;Function: void StopAudio(void)
  571. ;Short:    Stops all the channels so that sound no longer eminates from the
  572. ;          speakers.  NB: This function needs to support stopping of music objects.
  573.  
  574. _LIBStopAudio:
  575.     lea    $dff000,a1
  576.     lea    ChipZero,a0
  577.     move.l    a0,AUD0LC(a1)
  578.     move.l    a0,AUD1LC(a1)
  579.     move.l    a0,AUD2LC(a1)
  580.     move.l    a0,AUD3LC(a1)
  581.     move.w    #2,AUD0LEN(a1)
  582.     move.w    #2,AUD1LEN(a1)
  583.     move.w    #2,AUD2LEN(a1)
  584.     move.w    #2,AUD3LEN(a1)
  585.     move.w    #0,AUD0VOL(a1)
  586.     move.w    #0,AUD1VOL(a1)
  587.     move.w    #0,AUD2VOL(a1)
  588.     move.w    #0,AUD3VOL(a1)
  589.     rts
  590.  
  591. ;===================================================================================;
  592. ;                        CHECK IF SOUND IS CURRENTLY PLAYING
  593. ;===================================================================================;
  594. ;Function: LONG CheckSound(*Sound [a0])
  595. ;Result:   Returns NULL (FALSE) if not playing.
  596. ;Short:    This routine will check to see if someone else is playing in the given
  597. ;          Sound's channel.  If there is, we have obviously been pushed out of play.
  598.  
  599. _LIBCheckSound:
  600.     move.w    SNDP_LastChannel(a0),d0    ;d0 = Last channel.
  601.     beq.s    .noplay    ;>> = No last channel.
  602.     move.w    d0,d1    ;d1 = Channel.
  603.     add.w    d0,d0    ;d0 = *2
  604.     add.w    d0,d0    ;d0 = *4
  605.     lea    ChannelSounds(pc),a1    ;a1 = &ChannelSounds array.
  606.     cmp.l    (a1,d0.w),a0    ;a0 = Our sound still in play?
  607.     bne.s    .noplay    ;>> = Someone else is in the channel.
  608.  
  609.     ;Now check the channel hardware.
  610.  
  611.     add.w    #6,d1    ;d1 = (ChanNum)+6
  612.     move.w    $dff000+INTREQR,d0    ;d0 = INTREQR
  613.     btst    d1,d0    ;d0 = Check channel bit.
  614.     bne.s    .noplay    ;>> = Not playing.
  615.     moveq    #$01,d0    ;d0 = Sound is playing, return 1.
  616.     rts
  617.  
  618. .noplay    moveq    #$00,d0    ;d0 = Not playing.
  619.     rts
  620.  
  621. ;===================================================================================;
  622. ;                        CHANGE VOLUME OF CHANNEL
  623. ;===================================================================================;
  624. ;Function: LONG SetVolume(*Sound [a0], WORD Volume [d0])
  625. ;Short:    Sets a new volume for a sound.
  626. ;Result:   Returns the old volume.
  627.  
  628. _LIBSetVolume:
  629.     move.w    SND_Volume(a0),-(SP)    ;SP = Save the current volume to the stack.
  630.     cmp.w    #101,d0    ;d0 = Check the range.
  631.     bcc.s    .exit    ;>> = Out of range, exit.
  632.     move.w    d0,SND_Volume(a0)    ;a0 = Set volume change.
  633.     move.w    SNDP_LastChannel(a0),d1    ;d1 = Channel we are playing through.
  634.     add.w    d1,d1    ;d1 = ChanNum*2 [word]
  635.     add.w    d1,d1    ;d1 = ChanNum*2 [word]
  636.     move.l    .VolTab(pc,d1.w),a1    ;a1 = $Volume
  637.     lea    _Volumes,a0    ;a0 = $VolumeTable
  638.     add.w    d0,d0    ;d0 = (Volume)*2 [word]
  639.     move.w    (a0,d0.w),(a1)    ;a1 = Convert volume and insert.
  640. .exit    move.w    (SP)+,d0    ;d0 = Return the old volume.
  641.     rts
  642.  
  643. .VolTab    dc.l    $dff000+AUD0VOL    ;Actually illegal.
  644.     dc.l    $dff000+AUD0VOL
  645.     dc.l    $dff000+AUD1VOL
  646.     dc.l    $dff000+AUD2VOL
  647.     dc.l    $dff000+AUD3VOL
  648.  
  649. ;===================================================================================;
  650. ;                                  DATA
  651. ;===================================================================================;
  652.  
  653. ChannelPri:    dc.w  0,0,0,0    ;0,1,2,3
  654.  
  655. ;-----------------------------------------------------------------------------------;
  656. ;This array points to each Sound that last played through the available channels.
  657.  
  658. ChannelSounds:    dc.l  0    ;Null.
  659. CS1:        dc.l  0
  660. CS2:        dc.l  0
  661. CS3:        dc.l  0
  662. CS4:        dc.l  0
  663.  
  664. Chan1Vol:    dc.w  0
  665. Chan2Vol:    dc.w  0
  666. Chan3Vol:    dc.w  0
  667. Chan4Vol:    dc.w  0
  668.  
  669. ;-----------------------------------------------------------------------------------;
  670.  
  671. AUD_Name:    dc.b  "audio.device",0
  672.         even
  673.  
  674. AudioDevOpen:    dc.b  0
  675. SigBitNum:    dc.b  -1
  676.  
  677. AllocPort:    dc.l  0,0    ;succ, pred
  678.         dc.b  4,0    ;NT_MSGPORT
  679.         dc.l  0    ;name
  680.         dc.b  0,0    ;flags = PA_SIGNAL
  681.         dc.l  0    ;task
  682. ReqList:    dc.l  0,0,0    ;list head, tail and tailpred
  683.         dc.b  5,0
  684.         even
  685.  
  686. AllocReq:    dc.l  0,0
  687.         dc.b  0,127    ;NT_UNKNOWN, use maximum priority (127)
  688.         dc.l  0,AllocPort    ;name, replyport
  689.         dc.w  68    ;length
  690.         dc.l  0    ;io_Device
  691.         dc.l  0    ;io_Unit
  692.         dc.w  0    ;io_Command
  693.         dc.b  0,0    ;io_Flags, io_Error
  694.         dc.w  0    ;ioa_AllocKey
  695.         dc.l  sttempo    ;ioa_Data
  696.         dc.l  1    ;ioa_Length
  697.         dc.w  0,0,0    ;ioa_Period, Volume, Cycles
  698.         dc.w  0,0,0,0,0,0,0,0,0,0    ;ioa_WriteMsg
  699.  
  700. ;These values are the SoundTracker tempos (approx).
  701.  
  702. sttempo:    dc.w  $0f00
  703.  
  704. ;===================================================================================;
  705. ;                                CHIP DATA
  706. ;===================================================================================;
  707.  
  708.     SECTION    EmptyData,DATA_C
  709.  
  710. ChipZero:
  711.     dc.l    0,0
  712.  
  713. ;-----------------------------------------------------------------------------------;
  714. EndCode
  715.  
  716.